package com.bluexmicro.ota

import android.content.Context
import android.util.Log
import com.bluexmicro.ota.customface.CustomFaceModel
import com.bluexmicro.ota.dfu.FirmwareBean
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.json.JSONObject
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.util.zip.CRC32
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream

object FirmwareHelper {

    suspend fun unzipCustomFaceTemplate(context: Context, zip: File): CustomFaceModel =
        withContext(Dispatchers.IO) {
            val tempFiles = unzipFile(context, zip.path)
            //从中取出目录相关的json文件
            val catalogJsonFile = tempFiles.find { file ->
                file.extension.uppercase() == "JSON"
            } ?: throw IllegalStateException("无效压缩包")

            val templateFile = tempFiles.find { file ->
                file.extension.uppercase() == "BIN" || file.extension.uppercase() == "BXFACE"
            } ?: throw IllegalStateException("无效压缩包")

            var model: CustomFaceModel? = null
            val fis = FileInputStream(catalogJsonFile)
            try {
                val bytes = ByteArray(fis.available())
                fis.read(bytes)
                val jsonString = String(bytes)
                val jsonObj = JSONObject(jsonString)
                val screenWidth = jsonObj.getInt("screenWidth")
                val screenHeight = jsonObj.getInt("screenHeight")
                val backgroundStartIndex = jsonObj.getInt("backgroundStartIndex")
                val scriptStartIndex = jsonObj.getInt("scriptStartIndex")
                val scriptLen = jsonObj.getInt("scriptLen")
                val rawData = loadBinary(templateFile) ?: throw IllegalStateException("无效压缩包")
                model = CustomFaceModel(
                    screenWidth,
                    screenHeight,
                    backgroundStartIndex,
                    scriptStartIndex,
                    scriptLen,
                    rawData
                )
            } catch (e: Exception) {
                e.printStackTrace()
            } finally {
                fis.close()
            }
            return@withContext model ?: throw IllegalStateException("无效压缩包")
        }


    suspend fun unzipToFirmwares(context: Context, zip: File): List<FirmwareBean> =
        withContext(Dispatchers.IO) {
            return@withContext unzipToFirmwareAsync(context, zip)
        }

    fun unzipToFirmwareAsync(context: Context, zip: File): List<FirmwareBean> {
        //解压取得临时文件
        val tempFiles = unzipFile(context, zip.path)

        //从中取出目录相关的json文件
        val catalogJsonFile = tempFiles.find { file ->
            file.extension.uppercase() == "JSON"
        } ?: throw IllegalStateException("无效压缩包")

        val fis = FileInputStream(catalogJsonFile)
        val beans = mutableListOf<FirmwareBean>()
        try {
            val bytes = ByteArray(fis.available())
            fis.read(bytes)
            val jsonString = String(bytes)
            val jsonObj = JSONObject(jsonString)
            for (key in jsonObj.keys()) {
                val fileName = jsonObj.getString(key)
                val file = tempFiles.find {
                    it.endsWith(fileName)
                }
                if (file != null) {
                    val rawData = loadBinary(file)
                    if (rawData != null) {
                        val crc32 = CRC32()
                        crc32.update(rawData)
                        val crc32Value = crc32.value.toInt()
                        val bean = FirmwareBean(
                            idx = key.toInt().toByte(),
                            fileName,
                            rawData,
                            crc32Value
                        )
                        beans.add(bean)
                    }
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
        } finally {
            fis.close()
        }

        if (beans.isEmpty()) throw IllegalArgumentException("Invalid Zip File!")
        return beans
    }

    /**
     * clear file folder
     * @param path
     */
    private fun delete(path: String) {
        val file = File(path)
        val files = file.listFiles()
        if (files != null && files.isNotEmpty()) {
            for (temp in files) {
                if (temp.isFile) {
                    temp.delete()
                }
                if (temp.isDirectory) {
                    delete(temp.absolutePath)
                    temp.delete()
                }
            }
        }
    }

    /**
     * 解压到临时目录
     */
    private fun unzipFile(context: Context, zipPath: String): List<File> {
        val TAG = "BX-OTA"
        val otaCacheDir = "${context.cacheDir}${File.separator}dfu${File.separator}"
        val dir = File(otaCacheDir)
        if (dir.exists()) {
            //已存在dfu目录，删除旧的缓存,避免存储gu
            delete(otaCacheDir)
        } else {
            //没有该目录，生成dfu目录
            dir.mkdirs()
        }
        val outputFiles = mutableListOf<File>()
        val inputStream = FileInputStream(zipPath)
        val zipInputStream = ZipInputStream(inputStream)
        var fos: FileOutputStream? = null
        try {
            val buffer = ByteArray(1024 * 1024)
            var count: Int
            var zipEntry: ZipEntry?
            while (zipInputStream.nextEntry.also { zipEntry = it } != null) {
                if (!zipEntry!!.isDirectory) {
                    var fileName = zipEntry!!.name
                    fileName = fileName.substring(fileName.lastIndexOf('/') + 1)
                    Log.d(TAG, "解压到${otaCacheDir}${fileName}")
                    val file = File("${otaCacheDir}${fileName}")
                    file.createNewFile()
                    fos = FileOutputStream(file)
                    while ((zipInputStream.read(buffer).also { count = it }) > 0) {
                        fos.write(buffer, 0, count)
                    }
                    fos.close()
                    if (file.isHidden) {
                        //苹果系统会产生隐藏文件
                        file.delete()
                    } else {
                        Log.d(TAG, "有效文件：${otaCacheDir}${fileName}")
                        outputFiles.add(file)
                    }
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
        } finally {
            inputStream.close()
            zipInputStream.close()
            fos?.close()
        }
        return outputFiles
    }

    fun loadBinary(file: File): ByteArray? {
        var bytes: ByteArray? = null
        try {
            val fileInputStream = FileInputStream(file)
            bytes = ByteArray(fileInputStream.available())
            val size = fileInputStream.read(bytes)
            fileInputStream.close()
        } catch (e: java.lang.Exception) {
            e.printStackTrace()
        }
        return bytes
    }

}

